--- /dev/null
+commit bc4d0fec4f791fb198ff316849aaf3faba24b45a
+Author: Gaspard Thevenon <gaspard.thevenon@kitware.com>
+Date: Thu Feb 10 10:19:39 2022 +0100
+
+ Fix shader crash in Multi Volume Rendering without GradientTF
+
+ When using OpenGLGPUVolumeRayCastMapper with a MultiVolume,
+ not specifying a gradient opacity TF produced an error in
+ the composed shader (no argument would be given to functions which expected one),
+ and nothing was rendered, although this TF is supposed to be optional.
+
+ This commit fixes this by adding tests during the declarations of
+ those functions inside the shader, and by changing their signatures as needed.
+ Therefore, when no gradient opacity TF is given, no argument is expected
+ and none is given.
+
+diff --git a/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.cxx b/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.cxx
+index cdcec460ef..dfc65de04b 100644
+--- a/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.cxx
++++ b/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.cxx
+@@ -2415,7 +2415,8 @@ void vtkOpenGLGPUVolumeRayCastMapper::ReplaceShaderCompute(
+ vtkvolume::ComputeGradientOpacityMulti1DDecl(this->AssembledInputs));
+
+ vtkShaderProgram::Substitute(fragmentShader, "//VTK::ComputeColor::Dec",
+- vtkvolume::ComputeColorMultiDeclaration(this->AssembledInputs));
++ vtkvolume::ComputeColorMultiDeclaration(
++ this->AssembledInputs, vol->GetProperty()->HasGradientOpacity()));
+
+ vtkShaderProgram::Substitute(fragmentShader, "//VTK::ComputeLighting::Dec",
+ vtkvolume::ComputeLightingMultiDeclaration(ren, this, vol, numComps, independentComponents,
+@@ -2970,6 +2971,23 @@ bool vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::UpdateInputs(vtkRenderer* ren
+ this->ForceTransferInit();
+ }
+
++ if (this->MultiVolume)
++ {
++ bool hasGradient = this->Parent->AssembledInputs[0].Volume->GetProperty()->HasGradientOpacity();
++ for (auto& item : this->Parent->AssembledInputs)
++ {
++ if (item.second.Volume->GetProperty()->HasGradientOpacity() != hasGradient)
++ {
++ vtkGenericWarningMacro(
++ "Current implentation of vtkOpenGLGPUVolumeRayCastMapper does not support MultiVolume "
++ "where some volumes have a gradient opacity function and some others don't. "
++ "Rendering of the MultiVolume is disabled.");
++ success = false;
++ break;
++ }
++ }
++ }
++
+ return success;
+ }
+
+@@ -3106,7 +3124,10 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren, vtkVolume* vol
+ this->Impl->MultiVolume = multiVol && this->GetInputCount() > 1 ? multiVol : nullptr;
+
+ this->Impl->ClearRemovedInputs(renWin);
+- this->Impl->UpdateInputs(ren, vol);
++ if (!this->Impl->UpdateInputs(ren, vol))
++ {
++ return;
++ }
+ this->Impl->UpdateSamplingDistance(ren);
+ this->Impl->UpdateTransfer2DYAxisArray(ren, vol);
+ this->Impl->UpdateTransferFunctions(ren);
+diff --git a/Rendering/VolumeOpenGL2/vtkVolumeShaderComposer.h b/Rendering/VolumeOpenGL2/vtkVolumeShaderComposer.h
+index 766f36ab63..3406bfb431 100644
+--- a/Rendering/VolumeOpenGL2/vtkVolumeShaderComposer.h
++++ b/Rendering/VolumeOpenGL2/vtkVolumeShaderComposer.h
+@@ -1054,10 +1054,24 @@ std::string ComputeLightingMultiDeclaration(vtkRenderer* vtkNotUsed(ren), vtkVol
+ int lightingComplexity)
+ {
+ vtkVolumeProperty* volProperty = vol->GetProperty();
+- std::string shaderStr = std::string("\
++
++ std::string shaderStr = std::string();
++
++ // if no gradient TF is needed, don't add it into the function signature
++ if (volProperty->HasGradientOpacity())
++ {
++ shaderStr += std::string("\
+ \nvec4 computeLighting(vec3 texPos, vec4 color, const in sampler2D gradientTF, const in sampler3D volume, const int volIdx, int component)\
+ \n {\
+ \n vec4 finalColor = vec4(0.0);");
++ }
++ else
++ {
++ shaderStr += std::string("\
++ \nvec4 computeLighting(vec3 texPos, vec4 color, const in sampler3D volume, const int volIdx, int component)\
++ \n {\
++ \n vec4 finalColor = vec4(0.0);");
++ }
+
+ // Shading for composite blending only
+ int const shadeReqd = volProperty->GetShade() &&
+@@ -1243,7 +1257,8 @@ std::string ComputeColorDeclaration(vtkRenderer* vtkNotUsed(ren),
+ }
+
+ //--------------------------------------------------------------------------
+-std::string ComputeColorMultiDeclaration(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs)
++std::string ComputeColorMultiDeclaration(
++ vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs, bool useGradientTF)
+ {
+ std::ostringstream ss;
+ int i = 0;
+@@ -1274,13 +1289,28 @@ std::string ComputeColorMultiDeclaration(vtkOpenGLGPUVolumeRayCastMapper::Volume
+ }
+ else
+ {
+- ss << "vec4 computeColor(vec3 texPos, vec4 scalar, float opacity, const in sampler2D colorTF, "
+- "const in sampler2D gradientTF, const in sampler3D volume, const int volIdx)\n"
+- "{\n"
+- " return clamp(computeLighting(texPos, vec4(texture2D(colorTF,\n"
+- " vec2(scalar.w, 0.0)).xyz, opacity), gradientTF, volume, "
+- "volIdx, 0), 0.0, 1.0);\n"
+- "}\n";
++ if (useGradientTF)
++ {
++ ss
++ << "vec4 computeColor(vec3 texPos, vec4 scalar, float opacity, const in sampler2D colorTF, "
++ "const in sampler2D gradientTF, const in sampler3D volume, const int volIdx)\n"
++ "{\n"
++ " return clamp(computeLighting(texPos, vec4(texture2D(colorTF,\n"
++ " vec2(scalar.w, 0.0)).xyz, opacity), gradientTF, volume, "
++ "volIdx, 0), 0.0, 1.0);\n"
++ "}\n";
++ }
++ else
++ {
++ ss
++ << "vec4 computeColor(vec3 texPos, vec4 scalar, float opacity, const in sampler2D colorTF, "
++ "const in sampler3D volume, const int volIdx)\n"
++ "{\n"
++ " return clamp(computeLighting(texPos, vec4(texture2D(colorTF,\n"
++ " vec2(scalar.w, 0.0)).xyz, opacity), volume, "
++ "volIdx, 0), 0.0, 1.0);\n"
++ "}\n";
++ }
+ }
+
+ return ss.str();
+@@ -1828,14 +1858,18 @@ std::string ShadingMultipleInputs(
+
+ if (property->GetTransferFunctionMode() == vtkVolumeProperty::TF_1D)
+ {
++ std::string gradientopacity_param = (property->HasGradientOpacity())
++ ? input.GradientOpacityTablesMap[0] + std::string(", ")
++ : std::string();
++
+ toShaderStr << " g_srcColor.a = computeOpacity(scalar,"
+ << input.OpacityTablesMap[0]
+ << ");\n"
+ " if (g_srcColor.a > 0.0)\n"
+ " {\n"
+ " g_srcColor = computeColor(texPos, scalar, g_srcColor.a, "
+- << input.RGBTablesMap[0] << ", " << input.GradientOpacityTablesMap[0] << ", "
+- << "in_volume[" << i << "], " << i << ");\n";
++ << input.RGBTablesMap[0] << ", " << gradientopacity_param << "in_volume[" << i
++ << "], " << i << ");\n";
+
+ if (property->HasGradientOpacity())
+ {